﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using T.FAS.Runtime.Base.Entity;
using T.FAS.Runtime.Metadata.Dao;
using T.FAS.Runtime.Metadata.Entity;
using T.FAS.Runtime.Metadata.Service;
using T.FAS.Runtime.Metadata.SPI;
using T.ServiceComponent.Cache.Service;

namespace T.FAS.Runtime.Metadata.Client
{
    class MetaDataSecondCache : IMetaDataCache
    {

        private static CacheService cacheService = null;

        private string TenantID;
        private string VersionKey = "Version";
        private string DomainModelKey = "metaData";
        private string TimeStampKey = "TimeStamp";

        private MetaDataSecondCache()
        {
            cacheService = CacheService.GetInstance("DefaultPool");
            TenantID = UserUtil.GetCurrentUserTenantId();
        }

        private static object syncObj = new object();

        private static IMetaDataCache cache;

        public static IMetaDataCache GetSingleton()
        {
            if (cache == null)
            {
                lock (syncObj)
                {
                    if (cache == null)
                    {
                        cache = new MetaDataSecondCache();
                    }
                }
            }

            return cache;
        }
        public IMetaData Get(string metaDataId)
        {
            //return MetaDataHSFService.GetMetaData(metaDataId);

            var hashIdOrCode = this.GetHashId(metaDataId);
            string hashId = hashIdOrCode;
            var matchResult = Regex.Match(metaDataId, @"[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}", RegexOptions.IgnoreCase);
            using (T.ServiceComponent.Cache.Service.ICacheClient client = cacheService.GetClient())
            {
                if (matchResult.Success == false)
                {
                    var metaId = client.GetValueFromHash<string>(hashIdOrCode, DomainModelKey);
                    hashId = this.GetHashId(metaId);
                }
                if (string.IsNullOrEmpty(hashId) == false)
                {
                    var metaData = client.GetValueFromHash<TMetadata>(hashId, DomainModelKey);
                    if (metaData != null)
                    {
                        try
                        {
                            metaData.Content = new MetaDataContentManager().DeSerializeMetaData(metaData);
                            metaData.Content.MetaData = metaData;
                            metaData.ContentJSON = null;
                        }
                        catch (Exception e)
                        {
                            throw new FasException("", $"获取元数据({metaDataId})失败！{e}", e);
                        }
                    }
                    return metaData;
                }
                return null;
            }
        }


        public IMetaData TryGet(string metaDataId, out bool isSuccess)
        {
            try
            {
                var model = Get(metaDataId);
                isSuccess = true;

                return model;
            }
            catch (FasException e)
            {
                throw new Exception($"SecondCache-GetError:从redis中获取元数据({metaDataId})失败！{e}", e);
            }
            catch (Exception e)
            {
                LogUtil.Log("SecondCache-GetError:" + e.ToString());
                isSuccess = false;
                return null;
            }
        }


        public long GetTimeStamp(string metaDataId)
        {
            var hashId = this.GetHashId(metaDataId);
            using (T.ServiceComponent.Cache.Service.ICacheClient client = cacheService.GetClient())
            {
                return client.GetValueFromHash<long>(hashId, TimeStampKey);
            }
        }

        public void Set(IMetaData metaData)
        {
            try
            {
                if (metaData == null)
                    return;
                TMetadata tMetadata = (TMetadata)metaData.Clone();
                var hashId = this.GetHashId(metaData.ID);
                var hashCode = this.GetHashId(metaData.Code);
                var metaHashId = this.GetHashId(metaData.Code, metaData.MetaTypeID);
                metaData.Content.MetaData = metaData;
                tMetadata.ContentJSON = new MetaDataContentManager().SerializeMetaData(metaData);
                tMetadata.Content = null;
                using (T.ServiceComponent.Cache.Service.ICacheClient client = cacheService.GetClient())
                {
                    client.SetEntryInHash<TMetadata>(hashId, DomainModelKey, tMetadata);
                    client.SetEntryInHash<string>(hashCode, DomainModelKey, metaData.ID);
                    client.SetEntryInHash<string>(metaHashId, DomainModelKey, metaData.ID);
                    //client.SetEntryInHash<string>(hashId, VersionKey, metaData.CurrentVersion);
                    var startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));
                    long timestamp = (long)(metaData.LastModifyTime - startTime).TotalSeconds;
                    client.SetEntryInHash<long>(hashId, TimeStampKey, timestamp);
                    client.SetEntryInHash<long>(hashCode, TimeStampKey, timestamp);
                }
            }
            catch (Exception e)
            {
                LogUtil.Log("SecondCache-SetError:" + e.ToString());
                throw new Exception($"SecondCache-SetError:{e}", e);
            }
        }

        public string GetHashId(string metaDataId)
        {
            return "metaData:" + metaDataId;
        }

        public void Remove(string metaDataId)
        {
            var hashId = this.GetHashId(metaDataId);
            using (T.ServiceComponent.Cache.Service.ICacheClient client = cacheService.GetClient())
            {
                client.RemoveEntry(hashId);
            }
        }

        #region code type
        public IMetaData Get(string metaDataCode, string metaTypeID)
        {
            //return MetaDataHSFService.GetMetaData(metaDataCode, metaTypeID);

            var metaHashId = this.GetHashId(metaDataCode, metaTypeID);
            using (T.ServiceComponent.Cache.Service.ICacheClient client = cacheService.GetClient())
            {
                var metaDataID = client.GetValueFromHash<string>(metaHashId, DomainModelKey);
                if (string.IsNullOrEmpty(metaDataID) == false)
                {
                    var hashId = this.GetHashId(metaDataID);
                    var metaData = client.GetValueFromHash<TMetadata>(hashId, DomainModelKey);
                    if (metaData != null)
                    {
                        try
                        {
                            metaData.Content = new MetaDataContentManager().DeSerializeMetaData(metaData);
                            metaData.Content.MetaData = metaData;
                            metaData.ContentJSON = null;
                            return metaData;
                        }
                        catch (Exception e)
                        {
                            throw new FasException("", $"获取元数据({metaDataID})失败！{e}", e);
                        }
                    }
                    //return client.GetValueFromHash<TMetadata>(hashId, DomainModelKey);
                }
                return null;
            }
        }

        public IMetaData TryGet(string metaDataCode, string metaTypeID, out bool isSuccess)
        {
            try
            {
                var model = Get(metaDataCode, metaTypeID);
                isSuccess = true;

                return model;
            }
            catch (FasException e)
            {
                throw new Exception($"SecondCache-GetError:从redis中获取元数据({metaDataCode})失败！{e}", e);
            }
            catch (Exception e)
            {
                LogUtil.Log("SecondCache-GetError:" + e.ToString());
                isSuccess = false;
                return null;
            }
        }
        public string GetHashId(string metaDataCode, string metaTypeID)
        {
            return string.Format("metaData:{0}:{1}-{2}", TenantID, metaTypeID, metaDataCode);
        }
        public void Remove(string metaDataCode, string metaTypeID)
        {
            var metaHashId = this.GetHashId(metaDataCode, metaTypeID);
            using (T.ServiceComponent.Cache.Service.ICacheClient client = cacheService.GetClient())
            {
                var metaDataId = client.GetValueFromHash<string>(metaHashId, DomainModelKey);
                var hashId = this.GetHashId(metaDataId);
                client.RemoveEntry(hashId);
                client.RemoveEntry(metaHashId);
            }
        }
        #endregion
        #region 未用到
        public Action<string> CacheSyncAction { get => (id) => Set(GetFallback(id)); }

        //public bool IsLocalModel { get; set; }

        public void Add(IMetaData metaData)
        {
            if (metaData == null)
                return;

            var hashId = this.GetHashId(metaData.ID);
            using (T.ServiceComponent.Cache.Service.ICacheClient client = cacheService.GetClient())
            {
                //client.SetEntryInHash<IMetaData>(hashId, DomainModelKey, metaData);
                //client.SetEntryInHash<string>(hashId, VersionKey, metaData.CurrentVersion);
                var startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));
                long timestamp = (long)(metaData.LastModifyTime - startTime).TotalSeconds;
                client.SetEntryInHash<long>(hashId, TimeStampKey, timestamp);
            }
        }

        public string GetLatestVersion(string metaDataCode, string metaTypeID)
        {
            var hashId = this.GetHashId(metaDataCode, metaTypeID);
            using (T.ServiceComponent.Cache.Service.ICacheClient client = cacheService.GetClient())
            {
                return client.GetValueFromHash<string>(hashId, VersionKey);
            }
        }
        public IMetaData GetFallback(string metaDataCode, string metaTypeID)
        {
            return MetaDataHSFService.GetMetaDataByCode(metaDataCode, metaTypeID);
        }
        public string GetLatestVersion(string metaDataId)
        {
            var hashId = this.GetHashId(metaDataId);
            using (T.ServiceComponent.Cache.Service.ICacheClient client = cacheService.GetClient())
            {
                return client.GetValueFromHash<string>(hashId, VersionKey);
            }
        }
        public IMetaData GetFallback(string metaDataId)
        {
            return MetaDataHSFService.GetMetaData(metaDataId);
        }

        public bool IsCacheMetaDataValid(string metaDataId)
        {
            return true;
        }


        #endregion
    }
}
